﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.VersionControl.Client;
using Microsoft.TeamFoundation.VersionControl.Common;


namespace TFSTibcoDesignerRCSAdapter
{
    public static class RcsMethods
    {
        /// <summary>
        /// The driver for status. Returns True of False if file exists in version control system.
        /// Because this function is called too often we have used the configuration variable ByPassCheckIsRevisionControl
        /// which if is true then it does not perform this action
        /// </summary>
        /// <param name="sfilePath"></param>
        public static void IsRevisionControlled(string sfilePath)
        {
            if (!System.IO.File.Exists(sfilePath))
            {
                Console.Out.Write("false");
                return;
            }
            else if (SystemConfig.Default.ByPassCheckIsRevisionControl)
            {
                Console.Out.Write("true");
                return;
            }
            using (var tfsOp = new TfsOperations(sfilePath))
            {
                Console.Out.Write(tfsOp.IsRevisionControlled(sfilePath));
            }
        }
        
        #region Support functions
        /// <summary>
        /// Scripts should return true  if the RCS system requires directories to be in editable  
        /// or checked-out mode before items can be added or deleted from the directories.
        /// And it is used in startup
        /// </summary>
        public static void FoldersRequireLockForParentWritability()
        {
            Console.Out.Write("false");
        }

        /// <summary>
        /// Callback to return whether the RCS system supports file locking.
        /// For SVN this doesn't quite work because files are always writable.
        /// From the Svn's adapter perspective ALL files are always checkedout.
        /// If we return false, revert action is disabled. a lock.
        /// </summary>
        public static void SupportsLocking()
        {
            Console.Out.Write("true");
        }

        /// <summary>
        /// if false, TIBCO Designer won't allow commits via the RCS adapter
        /// Gets this info from appconfig variable SupportsCheckIns
        /// </summary>
        public static void SupportsCommit()
        {
            Console.Out.Write(SystemConfig.Default.SupportsCheckIns?"true":"false");
        }

        /// <summary>
        /// Let TIBCO Designer recurse it for us. Returning true from here
        /// could improve performance for some edit/revert operations
        /// at the expense of implementing recursive because Adapter will berform recursive operations.
        /// If false then tibco designer calls adapter for every file.
        /// </summary>
        public static void SupportsRecursiveLock()
        {
            //todo: check if bettere return true
            Console.Out.Write("true");
        }

        /// <summary>
        /// The Script always returns false to this command. All updates must be performed using the RCS's tools
        /// It returns true when tibco designer can perform Synchronise (= get Latest Version)
        /// </summary>
        public static void SupportsSynchronize()
        {
            LoggingMethods.CleanUpLogFile();
            Console.Out.Write("true");
        }

        /// <summary>
        /// if true, TIBCO Designer will ask for comments on add operation
        /// Will get this info from configuration variable
        /// </summary>
        public static void WantsCommentOnAdd()
        {
            Console.Out.Write((SystemConfig.Default.NeedsCommentsOnAdd ? "true" : "false"));
        }

        /// <summary>
        /// Callback to return a list of files that should be ignored by TIBCO Designer
        /// for svn these are the '.svn' directories. TIBCO Designer will not show these
        /// files in the project. Return one file name per line, when specifying
        /// directories, TIBCO Designer will not traverse them, so no need to ommit names
        /// inside of ignored directories.
        /// </summary>
        public static void SpecialVFileNames()
        {
            //do nothing for tfs
        }

        /// <summary>
        /// This callback controls whether folders require a
        /// recursive lock. If this returns true, a revert will trigger
        /// a recursive revert going up the project tree. Svn can revert
        /// individual files or folders. When the command is configured to true, TIBCO Designer requires 
        /// that all folders leading to the desired resource be unlocked for editing. Similarly,
        ///  when reverting, all folders containing the resource will be reverted and locked together.
        /// </summary>
        public static void FoldersRequireRecursiveLock()
        {
            Console.Out.Write("false");
        }
        #endregion

        /// <summary>
        /// This command is sent in response to the user selecting the View RCS Info for Resource command 
        /// in TIBCO Designer. The script should return information about the state of the resource by 
        /// writing to stdout.
        /// http://msdn.microsoft.com/en-us/library/microsoft.teamfoundation.versioncontrol.client.versioncontrolserver.querypendingsets%28v=VS.80%29.aspx
        /// http://blogs.msdn.com/b/buckh/archive/2006/03/15/552288.aspx
        /// </summary>
        /// <param name="sfilePath"></param>
        public static void Info(string sfilePath)
        {
            /////sfilePath = @"D:/dev/TIBCO/IB/Source/Code/TestProject/TestFolder/Folder/.folder";
            var retval = "";

            using (var tfsOp = new TfsOperations(sfilePath))
            {
                if (!tfsOp.IsRevisionControlled(sfilePath))
                {
                    retval = "Item has not been added in TFS!";
                }
                else
                {
                    retval = (tfsOp.GetPendingChanges(sfilePath).Count > 0)
                                 ? "Item has Pending changes"
                                 : "Item has not any Pending changes";
                }
                Console.Out.Write(retval);
            }
        }

        /// <summary>
        /// This Function reverts changes back. For TFS it performs the Undo Pending changes. It will lock again file.
        /// </summary>
        /// <param name="sfilePath"></param>
        /// <param name="isRecursive"></param>
        /// <returns></returns>
        public static int Revert(string sfilePath, bool isRecursive)
        {
            //sfilePath = @"D:/dev/TIBCO/IB/Source/Code/TestProject/TestFolder/Folder/.folder";
            
            if (isRecursive)
                sfilePath = FixFolderFile(sfilePath);
            using (var tfsOp = new TfsOperations(sfilePath))
            {
                if (tfsOp.IsRevisionControlled(sfilePath))
                {
                    return tfsOp.UndoPendingChanges(sfilePath, isRecursive) ? 0 : 1;
                }
                else
                {
                    return 0;
                }
            }
        }

        /// <summary>
        /// This is the method that we dispatch 'add' file requests. Recursive Additions performed by Tibco designer
        /// </summary>
        /// <param name="sfilePath"></param>
        /// <returns></returns>
        public static int Add(string sfilePath)
        {
            ////////sfilePath = @"D:\dev\TIBCO\IB\Source\Code\TestProject\Folder\.folder";
            using (var tfsOp = new TfsOperations(sfilePath))
            {
                if (tfsOp.AddItem(sfilePath))
                    return 0;
                else
                    return 1;
            }
        }

        /// <summary>
        /// Performs Check out for specific Path. This also releases the lock from files-folders and user can edit them
        /// This operation can be performed recursively.
        /// </summary>
        /// <param name="sfilePath"></param>
        /// <param name="isRecursive"></param>
        /// <returns></returns>
        public static int Edit(string sfilePath, bool isRecursive)
        {
           // sfilePath = @"D:/dev/TIBCO/IB/Source/Code/TestProject/TestFolder/.folder";
            if (isRecursive)
                sfilePath = FixFolderFile(sfilePath);
            using (var tfsOp = new TfsOperations(sfilePath)) { 
                if (tfsOp.CheckOutItem(sfilePath, isRecursive))
                    return 0;
                else
                    return 1;
            }
            
        }

        /// <summary>
        /// This method returns the status of the project directory
        /// If there's nothing to check in we set the stderr with a
        /// message. The exit code of 1, will be interpreted as an error
        /// and TIBCO Designer will raise a Dialog.
        /// </summary>
        /// <returns></returns>
        public static int CommitPreview()
        {
            int returnvalue = 0;
            //Get Tibco designer current directory (projects'one)
            var currentFolder = System.IO.Directory.GetCurrentDirectory(); 
            //////  currentFolder = @"D:\dev\TIBCO\IB\Source\Code\TestProject";
            using (var tfsOp = new TfsOperations(currentFolder))
            {
                var pendingchanges = tfsOp.GetPendingChangesStringFormat(currentFolder);

                if (pendingchanges.Equals("No changes exist to be performed"))
                {
                    LoggingMethods.Logerr("Nothing to check-in!");
                    returnvalue = 1;
                }
                else
                {
                    var Conflicts = tfsOp.EvaluateCheckIn(tfsOp.GetPendingChanges(currentFolder));
                    if (!Conflicts.Equals(""))
                    {
                        LoggingMethods.Logerr(Conflicts);
                        returnvalue = 1;
                    }
                    else
                    {
                        Console.Out.WriteLine(pendingchanges);
                        returnvalue = 0;
                    }
                }
            }
            return returnvalue;
        }

        /// <summary>
        /// The commit driver Performs a commit - checkin in the whole project. Comment param is used to be added in TFS checkin
        /// </summary>
        /// <param name="comment"></param>
        /// <returns></returns>
        public static int Commit(string comment)
        {
            if (String.IsNullOrEmpty(comment))
            {
                comment = "No comment Supplied.";
            }
            //Get Tibco designer current directory (projects'one)
            var currentFolder = System.IO.Directory.GetCurrentDirectory();
            //////////////////////////currentFolder =@"D:\dev\TIBCO\IB\Source\Code\TestProject\";
            using (var tfsOp = new TfsOperations(currentFolder))
            {
                if (tfsOp.CheckInPendingChanges(currentFolder, comment))
                    return 0;
                else
                    return 1;
            }

        }

        /// <summary>
        /// Performs a TFS Deletion of file or folder
        /// </summary>
        /// <param name="sfilepath"></param>
        /// <returns></returns>
        public static int Delete(string sfilePath)
        {
            //sfilepath = @"D:/dev/TIBCO/IB/Source/Code/TestProject/Folder/Folder/Process Definition (1).process";
            sfilePath = FixFolderFile(sfilePath);
            using (var tfsOp = new TfsOperations(sfilePath))
            {
                if (tfsOp.DeleteItem(sfilePath))
                    return 0;
                else
                    return 1;
            }
        }
        public static int UpdatePreview()
        {
            int returnvalue = 0;
            //Get Tibco designer current directory (projects'one)
            var currentFolder = System.IO.Directory.GetCurrentDirectory();
            //////  currentFolder = @"D:\dev\TIBCO\IB\Source\Code\TestProject";

            using (var tfsOp = new TfsOperations(currentFolder))
            {
                var pendingchanges = tfsOp.GetPendingChangesStringFormat(currentFolder);

                if (pendingchanges.Equals("No changes exist to be performed"))
                {
                    LoggingMethods.Logerr("There are not any pending changes in the project so you can proceed in Get Latest version.");
                    returnvalue = 1;
                }
                else
                {
                    Console.Out.WriteLine("There are pending changes: \r\n" + pendingchanges + "\r\n Are you sure you want to proceed?");
                    returnvalue = 0;
                }
            }
            return returnvalue;
        }

        /// <summary>
        /// Performs an update in the project by getting the latest version from TFS. This should be done in the 
        /// current Project directory and is performed by the synchronise button from designer.
        /// </summary>
        /// <returns></returns>
        public static int Update()
        {
            //Get Tibco designer current directory (projects'one)
            var currentFolder = System.IO.Directory.GetCurrentDirectory();
            /////////////currentFolder =@"D:\dev\TIBCO\IB\Source\Code\TestProject\";

            using (var tfsOp = new TfsOperations(currentFolder))
            {
                if (tfsOp.GetLatestVersion(currentFolder))
                    return 0;
                else
                    return 1;
            }

        }

        public static string Encrypt(string stext)
        {
            using (var tfsOp = new TfsOperations())
            {
                return tfsOp.Encrypt(stext);
            }

        }
        public static string Decrypt(string stext)
        {
            using (var tfsOp = new TfsOperations())
            {
                return tfsOp.Decrypt(stext);
            }

        }

        /// <summary>
        /// Gets a file path and if this refers to a folder (.folder file) returns the full filapath 
        /// of the folder and not ths .folder file. It is used in order to perform recursive operations in the folder and not file.
        /// </summary>
        /// <param name="sfilepath"></param>
        /// <returns></returns>
        private static string FixFolderFile(string sfilepath)
        {
            string filename = "";
            string filepath = "";

            if (sfilepath.IndexOf("\\") > 0)
            {
                filename = sfilepath.Substring(sfilepath.LastIndexOf("\\") + 1);
                filepath = sfilepath.Substring(0, sfilepath.LastIndexOf("\\"));
            }
            else if (sfilepath.IndexOf("/") > 0)
            {
                filename = sfilepath.Substring(sfilepath.LastIndexOf("/") + 1);
                filepath = sfilepath.Substring(0, sfilepath.LastIndexOf("/"));
            }
            else
            {
                filename = sfilepath;
            }
            if (filename.Equals(".folder") || filename.IndexOf(".substvar") > 0)
            {
                sfilepath = filepath;
            }

            return sfilepath;
        }
        
    }
}
